/******************************************
 * Métodos Numéricos - TP1 "Mandelzoom"
 *
 * bigfloat.h
 * Declaración de la clase BigFloat (flotante de precisión arbitraria)
 *
 ******************************************/

#ifndef __BIGFLOAT_H__
#define __BIGFLOAT_H__

#include <iostream>
#include "math.h"
#include <cmath>

using namespace std;

/*************************************************************************************
* Notar que el 0 puede representarse de muchas formas con esta estructura interna.
* Decidimos que sea siempre que la mantisa tenga solamente ceros. Esto implica que
* hay dos por cada valor del exponente, uno negativo y otro positivo. Todos cumplen
* que son elemento neutro en la suma y elemento absorvente en la multiplicación.
**************************************************************************************/

/**
 * Número real de coma flotante con precisión arbitraria.
 */
class BigFloat{
public:

    /**
     * Constructor default. Inicializa su valor en 0.
     */
    BigFloat(const int _precision);

    /**
     * Constructor por copia.
     */
    BigFloat(const BigFloat& otro);

    /**
     * Operador de asignación que realiza una copia. Requiere que tengan la misma precisión.
     */

    BigFloat& operator=(const BigFloat& otro);

    /**
     * Construye un BigFloat a partir de un array de char.
     */
    BigFloat(int _precision, char* c);

    /**
     * Construye un BigFloat a partir de un double
     * Suponemos que d >= 0 por como se usa la función
     * La mantisa de un double tiene 52 bits es decir tiene 16 o menos dígitos decimales,usamos
     * esa cota para tomar los digitos del double al pasarlos a char[]
     * Suponemos una precision maxima de 6 digitos (si se quiere mas cambiar char format[10])
     */
    BigFloat(int _precision, double d);

    /**
     * Construye un BigFloat a partir de sus campos:
     * precision, signo, mantisa y exponente.
     * El array que contiene la mantisa se copia.
     */
    BigFloat(int _precision, bool _signo, short _mantisa[], int exponente);

    /**
     * Destructor de BigFloat.
     */
    ~BigFloat();

    /**
     * Suma a este BigFloat otro. Retorna this.
     */
    BigFloat& sumar(const BigFloat& n);

    /**
     * Resta de este BigFloat otro. Retorna this.
     */
    BigFloat& restar(const BigFloat& n);

    /**
     * Multiplica este BigFloat por otro. Retorna this.
     */
    BigFloat& multiplicar(const BigFloat& n);

    /**
     * Multiplica este BigFloat por sí mismo. Retorna this.
     */
    BigFloat& cuadrar();

    /**
     * Indica si el BigFloat es mayor que cero.
     */
    bool positivo() const;

    /**
     * Indica si este BigFloat es mayor que el pasado por parámetro.
     */
    bool mayor(const BigFloat& que) const;

    /**
     * Calcula la división entre dos BigFloat's, sujeto a las siguientes
     * condiciones:
     *      - ambos parámetros son positivos (de no ser así los toma como si lo fueran);
     *      - num < 10;
     *      - el resultado estará entre 40 y 4000. (luego div < 1/4);
     */
    static int razon(const BigFloat& num, const BigFloat& div);

    /**
     * Muestra el BigFloat en un stream de salida.
     */
    ostream& mostrar(ostream& out) const;

    /**
     * Compara el BigFloat con un string, si son distintos termina la ejecución del programa.
     * Es de utilidad para el testeo.
     */
    void asegurar(const string s) const;

private:

    bool signo;

    /** Mantisa compuesta por dígitos decimales. Está normalizada, es decir que el primer elemento es mayor a cero. */
    short* mantisa;
    
    /** Exponente */
    int exp;

    /** Precisión o largo de la mantisa (en dígitos decimales) */
    int precision;

    /**
     * Transforma el número representado por los primeros largo digitos de la mantisa a un int.
     * Requiere: largo <= precision
     */
    int mantisaToInt(const int largo) const;

    /**
     * Realiza la suma y la resta de BigFloats dependiendo de un flag resta (si es 0 suma, sino resta).
     */
    void sumaYResta(const BigFloat& n, const bool resta);
    
    /*
     * Valor auxiliar para implementación dummy basada en long double.
     */
    long double val;

};

/**
 * Sobrecarga de operator<< que muestra el BigFloat en un stream.
 */
ostream& operator<<(ostream& out, const BigFloat& n);

#endif
